home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows 95 API Bible
/
Windows 95 API Bible 3 Disc Set.iso
/
Win32 API Bible Book 3 of 3
/
CHAPTE15
/
WAVINOUT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-28
|
29KB
|
826 lines
#include <windows.h>
#include <stdio.h>
#include "WavInOut.h"
#if defined (WIN32)
#define IS_WIN32 TRUE
#else
#define IS_WIN32 FALSE
#endif
#define IS_NT IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
#define IS_WIN32S IS_WIN32 && (BOOL)(!(IS_NT) && (LOBYTE(LOWORD(GetVersion()))<4))
#define IS_WIN95 (BOOL)(!(IS_NT) && !(IS_WIN32S)) && IS_WIN32
HINSTANCE hInst; // current instance
LPCTSTR lpszAppName = "MyApp";
LPCTSTR lpszTitle = "Wave In/Out";
BOOL RegisterWin95( CONST WNDCLASS* lpwc );
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
MSG msg;
HWND hWnd;
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, lpszAppName);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = lpszAppName;
wc.lpszClassName = lpszAppName;
if ( IS_WIN95 )
{
if ( !RegisterWin95( &wc ) )
return( FALSE );
}
else if ( !RegisterClass( &wc ) )
return( FALSE );
hInst = hInstance;
hWnd = CreateWindow( lpszAppName,
lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL,
NULL,
hInstance,
NULL
);
if ( !hWnd )
return( FALSE );
ShowWindow( hWnd, nCmdShow );
UpdateWindow( hWnd );
while( GetMessage( &msg, NULL, 0, 0) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return( msg.wParam );
}
BOOL RegisterWin95( CONST WNDCLASS* lpwc )
{
WNDCLASSEX wcex;
wcex.style = lpwc->style;
wcex.lpfnWndProc = lpwc->lpfnWndProc;
wcex.cbClsExtra = lpwc->cbClsExtra;
wcex.cbWndExtra = lpwc->cbWndExtra;
wcex.hInstance = lpwc->hInstance;
wcex.hIcon = lpwc->hIcon;
wcex.hCursor = lpwc->hCursor;
wcex.hbrBackground = lpwc->hbrBackground;
wcex.lpszMenuName = lpwc->lpszMenuName;
wcex.lpszClassName = lpwc->lpszClassName;
// Added elements for Windows 95.
//...............................
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.hIconSm = LoadImage(wcex.hInstance, lpwc->lpszClassName,
IMAGE_ICON, 16, 16,
LR_DEFAULTCOLOR );
return RegisterClassEx( &wcex );
}
LRESULT CALLBACK About( HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return (TRUE);
case WM_COMMAND:
if ( LOWORD(wParam) == IDOK
|| LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, TRUE);
return (TRUE);
}
break;
}
return (FALSE);
}
#define PLAYBACK_BUFFER_SIZE 327680L
#define DATABLOCK_SIZE 32768L
#define MAX_BUFFERS 2 // double buffer
#define MSG_LEN 128
// global variables
//.................
enum Status
{
StatusOkay,
StatusError,
StatusDone,
} eStatus;
char msg[MSG_LEN+1];
static HWAVEIN hwi;
static HWAVEOUT hwo;
static WAVEHDR* wh[MAX_BUFFERS];
// temp buffer for this example
//.............................
static VOID* pPlaybackBuffer;
static DWORD nPlaybackBufferPos = 0L; // position in playback buffer
static DWORD nPlaybackBufferLen = 0L; // total data in playback buffer
BOOL TestOpenInputDevice();
BOOL TestOpenOutputDevice();
VOID StartRecordTest (HWND hWnd);
VOID StopRecordTest (HWND hWnd);
VOID StartPlayBackTest(HWND hWnd);
VOID StopPlayBackTest (HWND hWnd);
VOID LoadDataBlock(WAVEHDR* lpwh);
VOID AllocBuffers();
VOID CleanUpBuffers();
VOID CALLBACK waveInProc( HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 );
/*****************************************************************************
* WndProc
*
*
*
******************************************************************************/
#define USR_INBLOCK (WM_USER+101)
#define USR_OUTBLOCK (WM_USER+102)
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_COMMAND :
switch( LOWORD( wParam ) )
{
case IDM_TEST :
{
int i;
for (i = 0; i < MAX_BUFFERS; i++)
wh[i] = NULL;
eStatus = StatusOkay;
AllocBuffers();
if ( TestOpenInputDevice(hWnd) )
StartRecordTest(hWnd);
else
CleanUpBuffers();
}
break;
case IDM_ABOUT :
DialogBox( hInst, "AboutBox", hWnd, About );
break;
case IDM_EXIT :
DestroyWindow( hWnd );
break;
}
break;
case USR_INBLOCK :
{
// received data buffer block with recorded data,
// copy to playback buffer for use later
//...............................................
MMRESULT rc;
MMTIME mmtime;
LPWAVEHDR lpwh = (LPWAVEHDR)lParam;
if (eStatus == StatusOkay)
{
if (nPlaybackBufferPos + lpwh->dwBytesRecorded <= PLAYBACK_BUFFER_SIZE)
{
// copy data buffer block to playback buffer
//..........................................
memcpy( ((char*)pPlaybackBuffer+nPlaybackBufferPos), lpwh->lpData, lpwh->dwBytesRecorded);
nPlaybackBufferPos += lpwh->dwBytesRecorded;
nPlaybackBufferLen += lpwh->dwBytesRecorded;
mmtime.wType = TIME_BYTES;
waveInGetPosition(hwi, &mmtime, sizeof(MMTIME));
wsprintf(msg, "%s - Recorded %ld bytes", lpszTitle, mmtime.u.cb);
SetWindowText(hWnd, msg);
// reuse data buffer block
//........................
rc = waveInPrepareHeader(hwi, lpwh, sizeof(WAVEHDR));
if (rc == MMSYSERR_NOERROR)
rc = waveInAddBuffer(hwi, lpwh, sizeof(WAVEHDR));
if (rc != MMSYSERR_NOERROR)
{
waveInGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
eStatus = StatusError; // signal to shut down the process
}
}
else
{
eStatus = StatusDone;
StopRecordTest(hWnd);
}
}
break;
}
case MM_WOM_DONE :
{
PostMessage(hWnd, USR_OUTBLOCK, 0, lParam);
break;
}
case USR_OUTBLOCK :
{
// received data buffer block that has
// completed playback, reload and requeue
//.......................................
MMRESULT rc;
MMTIME mmtime;
LPWAVEHDR lpwh = (LPWAVEHDR)lParam;
mmtime.wType = TIME_BYTES;
waveOutGetPosition(hwi, &mmtime, sizeof(MMTIME));
wsprintf(msg, "%s - Played %ld bytes", lpszTitle, mmtime.u.cb);
SetWindowText(hWnd, msg);
if (eStatus == StatusOkay)
{
LoadDataBlock(lpwh); // changes eStatus to StatusDone when
// playback buffer is exhausted
if (eStatus == StatusOkay)
{
rc = waveOutPrepareHeader(hwo, lpwh, sizeof(WAVEHDR));
// write buffers to the queue
if (rc == MMSYSERR_NOERROR)
rc = waveOutWrite(hwo, lpwh, sizeof(WAVEHDR));
if (rc != MMSYSERR_NOERROR)
{
waveOutGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
StopPlayBackTest(hWnd); // free allocated memory
eStatus = StatusError;
}
}
}
else
{
// check if all of the buffers have come back yet
//...............................................
int i;
for (i = 0; i < MAX_BUFFERS; i++)
{
if (wh[i]->dwFlags & WHDR_INQUEUE)
return(0L); // not done yet, wait
}
StopPlayBackTest(hWnd);
}
break;
}
case WM_DESTROY :
PostQuitMessage(0);
break;
default :
return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
}
return( 0L );
}
/*****************************************************************************
* waveInProc
*
*
*
******************************************************************************/
VOID CALLBACK waveInProc( HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
switch (uMsg)
{
case WIM_OPEN :
case WIM_CLOSE:
break; // don't care
case WIM_DATA :
{
// post message to process this input block received
// NOTE: callback cannot call other waveform functions
//....................................................
PostMessage((HWND)dwInstance, USR_INBLOCK, 0, dwParam1);
break;
}
}
}
/*****************************************************************************
* TestOpenInputDevice
*
*
*
******************************************************************************/
BOOL TestOpenInputDevice(HWND hWnd)
{
WAVEINCAPS wic;
WAVEFORMATEX wfx;
UINT nDevId;
MMRESULT rc;
UINT nMaxDevices = waveInGetNumDevs();
hwi = NULL;
nPlaybackBufferPos = 0L; // position in playback buffer
nPlaybackBufferLen = 0L; // total data in playback buffer
eStatus = StatusOkay; // reset status
for (nDevId = 0; nDevId < nMaxDevices; nDevId++)
{
rc = waveInGetDevCaps(nDevId, &wic, sizeof(wic));
if (rc == MMSYSERR_NOERROR)
{
// attempt 44.1 kHz stereo if device is capable
if (wic.dwFormats & WAVE_FORMAT_4S16)
{
wfx.nChannels = 2; // stereo
wfx.nSamplesPerSec = 44100; // 44.1 kHz (44.1 * 1000)
}
else
{
wfx.nChannels = wic.wChannels; // use DevCaps # channels
wfx.nSamplesPerSec = 22050; // 22.05 kHz (22.05 * 1000)
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = 8;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
// open waveform input device
//...........................
rc = waveInOpen(&hwi, nDevId, &wfx, (DWORD)(VOID*)waveInProc, (DWORD)hWnd,
CALLBACK_FUNCTION);
if (rc == MMSYSERR_NOERROR)
break;
else
{
waveInGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
return(FALSE);
}
}
}
// device not found, error condition
//..................................
if (hwi == NULL)
{
eStatus = StatusError;
return(FALSE);
}
return(TRUE);
}
/*****************************************************************************
* StartRecordTest
*
*
*
******************************************************************************/
VOID StartRecordTest(HWND hWnd)
{
MMRESULT rc;
int i;
MMTIME mmtime;
// prepare buffer blocks and add to input queue
//.............................................
for (i = 0; i < MAX_BUFFERS; i++)
{
rc = waveInPrepareHeader(hwi, wh[i], sizeof(WAVEHDR));
// add buffers to the input queue
if (rc == MMSYSERR_NOERROR)
rc = waveInAddBuffer(hwi, wh[i], sizeof(WAVEHDR));
if (rc != MMSYSERR_NOERROR)
{
waveInGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
StopRecordTest(hWnd); // free allocated memory
return;
}
}
// start recording
//................
rc = waveInStart(hwi);
// test waveInGetPosition() function
mmtime.wType = TIME_SAMPLES;
rc = waveInGetPosition(hwi, &mmtime, sizeof(MMTIME));
if (rc != MMSYSERR_NOERROR)
{
waveInGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
}
}
/*****************************************************************************
* StopRecordTest
*
*
*
******************************************************************************/
VOID StopRecordTest(HWND hWnd)
{
int i;
int nReply;
// stop recording
//...............
waveInStop(hwi);
waveInReset(hwi);
// Unprepare headers
//..................
for (i = 0; i < MAX_BUFFERS; i++)
waveInUnprepareHeader(hwi, wh[i], sizeof(WAVEHDR));
waveInClose(hwi);
// check if user wants to hear what was recorded
//..............................................
nReply = MessageBox(hWnd, "Do you want to playback what has been recorded?",
"Test", MB_ICONQUESTION|MB_YESNO);
if (nReply == IDYES && TestOpenOutputDevice(hWnd) )
StartPlayBackTest(hWnd);
else
{
CleanUpBuffers();
SetWindowText(hWnd, lpszTitle);
}
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*****************************************************************************
* TestOpenOutputDevice
*
*
*
******************************************************************************/
BOOL TestOpenOutputDevice(HWND hWnd)
{
WAVEOUTCAPS woc;
WAVEFORMATEX wfx;
UINT nDevId;
MMRESULT rc;
UINT nMaxDevices = waveOutGetNumDevs();
hwo = NULL;
nPlaybackBufferPos = 0L; // position in playback buffer
eStatus = StatusOkay; // reset status
for (nDevId = 0; nDevId < nMaxDevices; nDevId++)
{
rc = waveOutGetDevCaps(nDevId, &woc, sizeof(woc));
if (rc == MMSYSERR_NOERROR)
{
// attempt 44.1 kHz stereo if device is capable
if (woc.dwFormats & WAVE_FORMAT_4S16)
{
wfx.nChannels = 2; // stereo
wfx.nSamplesPerSec = 44100; // 44.1 kHz (44.1 * 1000)
}
else
{
wfx.nChannels = woc.wChannels; // use DevCaps # channels
wfx.nSamplesPerSec = 22050; // 22.05 kHz (22.05 * 1000)
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.wBitsPerSample = 8;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.cbSize = 0;
rc = waveOutOpen(&hwo, nDevId, &wfx, (DWORD)hWnd, 0,
CALLBACK_WINDOW);
if (rc == MMSYSERR_NOERROR)
{
DWORD dwVol;
// set volume level to at least 80%
rc = waveOutGetVolume( hwo, &dwVol );
if (rc == MMSYSERR_NOERROR)
if ( LOWORD(dwVol) < 0xCCCC ||
( wfx.nChannels == 2 && HIWORD(dwVol) < 0xCCCC ) )
rc = waveOutSetVolume( hwo, (DWORD)MAKELONG( 0xCCCC, 0xCCCC ) );
}
if (rc != MMSYSERR_NOERROR)
{
waveOutGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
return(FALSE);
}
break;
}
}
// device not found, error condition
//..................................
if (hwo == NULL)
return(FALSE);
return(TRUE);
}
/*****************************************************************************
* StartPlayBackTest
*
*
*
******************************************************************************/
VOID StartPlayBackTest(HWND hWnd)
{
MMRESULT rc;
int i;
WAVEOUTCAPS woc;
UINT nDevId;
DWORD dwPitch;
DWORD dwRate;
eStatus = StatusOkay;
rc = waveOutGetID(hwo, &nDevId);
rc = waveOutGetDevCaps(nDevId, &woc, sizeof(woc));
// increase pitch and playback rate by a multiplier of two
// if device supports this function
//........................................................
if (woc.dwSupport & WAVECAPS_PLAYBACKRATE)
{
rc = waveOutGetPlaybackRate(hwo, &dwRate);
rc = waveOutSetPlaybackRate(hwo, MAKELONG(HIWORD(dwRate)*2, LOWORD(dwRate)) );
}
if (woc.dwSupport & WAVECAPS_PITCH)
{
rc = waveOutGetPitch(hwo, &dwPitch);
rc = waveOutSetPitch(hwo, MAKELONG( HIWORD(dwPitch)*2, LOWORD(dwPitch)) );
}
// pause the device until the first buffers have been
// written to the device's queue
//...................................................
waveOutPause(hwo);
// prepare output buffer blocks
//.............................
for (i = 0; i < MAX_BUFFERS; i++)
{
// load data into data buffer block.
// the remaining data will be loaded later
// by the callback.
//........................................
LoadDataBlock(wh[i]);
// prepare the buffers
rc = waveOutPrepareHeader(hwo, wh[i], sizeof(WAVEHDR));
// write buffers to the queue
if (rc == MMSYSERR_NOERROR)
rc = waveOutWrite(hwo, wh[i], sizeof(WAVEHDR));
if (rc != MMSYSERR_NOERROR)
{
waveOutGetErrorText(rc, msg, MSG_LEN),
MessageBox(hWnd, msg, NULL, MB_OK);
StopPlayBackTest(hWnd); // free allocated memory
eStatus = StatusError;
return;
}
}
// start playback (device currently paused)
//.........................................
waveOutRestart(hwo);
}
/*****************************************************************************
* LoadDataBlock
*
*
*
******************************************************************************/
VOID LoadDataBlock(WAVEHDR* lpwh)
{
DWORD nLen;
if (nPlaybackBufferPos < nPlaybackBufferLen)
{
nLen = nPlaybackBufferLen - nPlaybackBufferPos;
if (nLen > DATABLOCK_SIZE)
nLen = DATABLOCK_SIZE;
memcpy(lpwh->lpData, ((char*)pPlaybackBuffer+nPlaybackBufferPos), nLen);
lpwh->dwBufferLength = nLen;
nPlaybackBufferPos += nLen;
}
else
eStatus = StatusDone;
}
/*****************************************************************************
* StopPlayBackTest
*
*
*
******************************************************************************/
VOID StopPlayBackTest(HWND hWnd)
{
MMRESULT rc;
int i;
// cleanup
//........
for (i = 0; i < MAX_BUFFERS; i++)
waveOutUnprepareHeader(hwo, wh[i], sizeof(WAVEHDR));
rc = waveOutClose(hwo);
CleanUpBuffers();
SetWindowText(hWnd, lpszTitle);
}
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*****************************************************************************
* AllocBuffers
*
*
*
******************************************************************************/
VOID AllocBuffers()
{
int i;
// allocate two WAVEHDR buffer blocks
//...................................
for (i = 0; i < MAX_BUFFERS; i++)
{
wh[i] = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(WAVEHDR) );
if (wh[i])
{
wh[i]->lpData = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
DATABLOCK_SIZE);
wh[i]->dwBufferLength = DATABLOCK_SIZE;
}
}
// allocate playback buffer - enough space to hold
// ten data buffer blocks of waveform sound data
//................................................
pPlaybackBuffer = HeapAlloc( GetProcessHeap(),
HEAP_ZERO_MEMORY,
PLAYBACK_BUFFER_SIZE);
}
/*****************************************************************************
* CleanUpBuffers
*
*
*
******************************************************************************/
VOID CleanUpBuffers()
{
int i;
// free the WAVEHDR buffer blocks
//...............................
for (i = 0; i < MAX_BUFFERS; i++)
{
if (wh[i] != NULL)
{
HeapFree(GetProcessHeap(), 0, wh[i]->lpData);
HeapFree(GetProcessHeap(), 0, wh[i]);
wh[i] = NULL;
}
}
// free playback buffer
//.....................
HeapFree(GetProcessHeap(), 0, pPlaybackBuffer);
}